package cn.edu.njuit.lesson9heros.myioc;

import cn.edu.njuit.lesson9heros.service.HeroService;
import cn.edu.njuit.lesson9heros.service.impl.GameServiceImpl;
import cn.edu.njuit.lesson9heros.service.impl.HeroServiceImpl;
import cn.edu.njuit.lesson9heros.service.impl.TeamServiceImpl;
import cn.edu.njuit.lesson9heros.utils.FileTool;

import java.io.File;
import java.io.FilenameFilter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

/**
 * 自定义ioc容器
 */
public class MyComponentFactory {
    /**
     * 实例容器
     */
    private static Map<String,Class> components=new HashMap<String,Class>();

    /**
     * 向容器放入实例化对象
     */
    public static void initComponents(){
        getClassList("cn.edu.njuit.lesson9heros");
        System.out.println("初始化");
    }

    /**
     * 获取实例
     * @param name 实例名称
     * @return
     */
    public static Object getComponent(String name){
        if(components.containsKey(name)){
            Class c=components.get(name);
            try {
                Object instance=c.getDeclaredConstructor().newInstance();
                processAutowired(c,instance);
                return instance;
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            return null;
        }else{
            //可以增加错误日志输出，未找到实例
            return null;
        }
    }

    public static void setComponent(String name,Class component){
        components.put(name,component);
    }

    private static void getClassList(String packageName){
        //根据包名获得运行路径
        String filePath= FileTool.packageFilePath(packageName);
        File files=new File(filePath);
        File [] classFiles=files.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(".class");
            }
        });
        if(classFiles!=null && classFiles.length>0){
            for (File classFile : classFiles) {
                String className=classFile.getName();
                try {
                    Class c=Class.forName(packageName+"."+className.replace(".class",""));
                    //如果包含注解
                    if(c.isAnnotationPresent(MyComponent.class)){
                        MyComponent annotation=(MyComponent)c.getAnnotation(MyComponent.class);
                        setComponent(annotation.name(),c);
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
        //遍历剩余子目录
        if(files.isDirectory()){
            String [] fileNames= files.list();
            for (String fileName : fileNames) {
                File file=new File(filePath+File.separator+fileName);
                if(file.isDirectory()){
                    getClassList(packageName+"."+fileName);
                }
            }
        }
    }

    private static void processAutowired(Class c,Object instance){
        Field[] fields= c.getDeclaredFields();
        for (Field field : fields) {
            //如果有自动装配注解
            if(field.isAnnotationPresent(MyAutowired.class)){
                Class type=field.getType();
                try {
                    //如果是接口，按名称进行实例化
                    if(type.isInterface()){
                        MyAutowired autoAutowired=(MyAutowired)field.getAnnotation(MyAutowired.class);
                        String typeName=autoAutowired.name();
                        if(typeName.equals("")){
                            typeName=field.getName();
                        }
                        Object fieldValue=getComponent(typeName);
                        field.set(instance,fieldValue);
                    }else{
                        Object fieldValue=type.getDeclaredConstructor().newInstance();
                        field.setAccessible(true);
                        //为自动装配的实例填值
                        field.set(instance,fieldValue);
                    }

                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }

            }
        }
    }
}
